package zelix.hack.hacks.automine;

import zelix.Core;
import zelix.hack.Hack;
import zelix.hack.HackCategory;
import zelix.hack.hacks.Search;
import zelix.utils.system.EnumChatFormatting;
import zelix.value.BooleanValue;
import zelix.value.Mode;
import zelix.value.ModeValue;
import zelix.value.NumberValue;
import zelix.utils.Wrapper;
import net.minecraft.block.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.MovementInput;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.event.InputUpdateEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
import org.lwjgl.opengl.GL11;
import zelix.utils.hooks.visual.ChatUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;

public class AutoMine extends Hack
{
	private Minecraft mc = Minecraft.getMinecraft();
	public static BooleanValue showPath = new BooleanValue("ShowPath",true);
	public static NumberValue delay = new NumberValue("DigDelay",10d,0d,1000d);
	public static NumberValue refreshdelay = new NumberValue("RefreshTime(Sec)",1d,0d,60d);
	public static NumberValue YCord = new NumberValue("YCord",5d,3d,100d);
	public static ModeValue mode = new ModeValue("Mode",new Mode("Simple", true), new Mode("Stone", false));
	public BooleanValue dia = new BooleanValue("Diamond", true);
	public BooleanValue gold = new BooleanValue("Gold",false);
	public BooleanValue iron = new BooleanValue("Iron",false);
	public BooleanValue lapis = new BooleanValue("Lapis",false);
	public BooleanValue emerald = new BooleanValue("Emerald",false);
	public BooleanValue coal = new BooleanValue("Coal",false);
	public BooleanValue redstone = new BooleanValue("Redstone",false);
	public BooleanValue quartz = new BooleanValue("Quartz",false);

	public AutoMine() {
		super("AutoMine", HackCategory.PLAYER);
		addValue(mode);
		addValue(showPath,delay,YCord);
		addValue(dia);
		addValue(gold);
		addValue(iron);
		addValue(lapis);
		addValue(emerald);
		addValue(coal);
		addValue(redstone);
		addValue(quartz);
		addValue(refreshdelay);
	}
	



	//路径
	private ArrayList<Vec3> path = new ArrayList<>();
	//xRay遍历出来的所有指定方块
	public static LinkedList<BlockPos> blocks = new LinkedList<BlockPos>();
	//本功能是否开启
	//public static boolean isActive = false;
	//需要破坏的方块
	public static BlockPos readyBreakBlock = null;
	//是否开始执行自动挖矿
	public static volatile boolean start = false;
	//是否已经规划好路线
	public static boolean PathReady = false;
	//执行第二次地下路径计算(第一次为地表)
	public static boolean tryTwo = false;
	//如果路径是向上的就跳跃起来在脚底放方块
	public static boolean shouldPlaceBlock = false;
	//遇到沙砾和沙子的时间等待助手
	private TimeHelper timeHelper = new TimeHelper();
	//readyBreakBlock被破坏后或者路径计算错误停滞原地10秒的时间助手
	private TimeHelper timeHelper2 = new TimeHelper();
	//碰到方块边缘但是不下去的时间助手
	private TimeHelper timeHelper3 = new TimeHelper();
	//全局时间助手
	private TimeHelper timeHelper4 = new TimeHelper();
	//抽取相对于位置的路径信息
	private int count = 0;
	//需要按下的按键，分别为W，A，S，D，SPACE，SHIFT
	public static String keyDown = "";
	//刷新时间
	//private final TimerUtils refresh = new TimerUtils();

	@Override
	public void onEnable(){
		//isActive = true;
		onEnableMod();
	}
	@Override
	public void onDisable(){
		//isActive = false;
		onDisableMod();
	}
	public void onEnableMod()
    {

    	if(!hasBlock()) {
    		onDisableMod();
    		ChatUtils.message(EnumChatFormatting.RED+"请放些方块在物品栏，以便上升时垫脚！");
    		return;

    	}
		//refresh.reset();
    	//isActive = true;
    	resetAllOptions();
		if (Core.hackManager.getHack("Search").isToggled()){
			for (BlockPos pos: Search.toRender)
			{
				Block bId = BlockUtils.getBlock(pos);

				if (!(bId instanceof BlockAir))
				{
					if(BlockUtils.getBlockMeta(pos) == 0 && isTarget(pos)) {
						int x = pos.getX();
						int y = pos.getY();
						int z = pos.getZ();
						boolean canBreak = true;
						boolean isLiquid = false;

						//方块上面不能是沙砾
						if(BlockUtils.getBlock(new BlockPos(x, y + 1, z)) instanceof BlockGravel) {
							canBreak = false;
						}

						//如果方块底下不是实心 那如果底下第三格是空气 就有问题
						if(!AutoMinePathFinder.isSafeToWalkOn(new BlockPos(x, y -  1, z)) && BlockUtils.getBlock(new BlockPos(x, y - 3, z)) instanceof BlockAir) {
							canBreak = false;
						}

						//方块底下三格都不能是流体
						for(int blockPosY = 1; blockPosY <= 3; blockPosY++) {
							if(BlockUtils.getBlock(new BlockPos(x, y - blockPosY, z)) instanceof BlockLiquid) {
								canBreak = false;
								isLiquid = true;
							}
						}

						//如果方块底下三格有流体那直接不执行
						if(!isLiquid) {
							for(int blockPosY = 1; blockPosY <= 3; blockPosY++) {
								if(!(BlockUtils.getBlock(new BlockPos(x, y - blockPosY, z)) instanceof BlockLiquid) && AutoMinePathFinder.isSafeToWalkOn(new BlockPos(x, y - blockPosY, z))) {
									canBreak = true;
								}
							}
						}

						//方块周围不能是流体
						loop:
						for (int x1 = x - 2; x1 <= x + 2; x1++)
						{
							for (int y1 = y; y1 <= y + 2; y1++)
							{
								for (int z1 = z - 2; z1 <= z + 2; z1++)
								{
									if (BlockUtils.getBlock(new BlockPos(x1, y1, z1)) instanceof BlockLiquid)
									{
										canBreak = false;
										break loop;
									}
								}
							}
						}

						if(canBreak) {
							blocks.add(pos);
						}
					}
				}
			}
		}else{
			for (int i = (int)(Wrapper.INSTANCE.mc().player.posX - 50); i <= (int)(Wrapper.INSTANCE.mc().player.posX + 50); i++)
			{
				for (int j = (int)(Wrapper.INSTANCE.mc().player.posZ - 50); j <= (int)(Wrapper.INSTANCE.mc().player.posZ + 50); j++)
				{
					for (int k = 5; k <= Wrapper.INSTANCE.mc().world.getHeight(); k++)
					{
						BlockPos pos = new BlockPos(i, k, j);
						Block bId = BlockUtils.getBlock(pos);

						if (!(bId instanceof BlockAir))
						{
							if(BlockUtils.getBlockMeta(pos) == 0 && isTarget(pos)) {
								int x = pos.getX();
								int y = pos.getY();
								int z = pos.getZ();
								boolean canBreak = true;
								boolean isLiquid = false;

								//方块上面不能是沙砾
								if(BlockUtils.getBlock(new BlockPos(x, y + 1, z)) instanceof BlockGravel) {
									canBreak = false;
								}

								//如果方块底下不是实心 那如果底下第三格是空气 就有问题
								if(!AutoMinePathFinder.isSafeToWalkOn(new BlockPos(x, y -  1, z)) && BlockUtils.getBlock(new BlockPos(x, y - 3, z)) instanceof BlockAir) {
									canBreak = false;
								}

								//方块底下三格都不能是流体
								for(int blockPosY = 1; blockPosY <= 3; blockPosY++) {
									if(BlockUtils.getBlock(new BlockPos(x, y - blockPosY, z)) instanceof BlockLiquid) {
										canBreak = false;
										isLiquid = true;
									}
								}

								//如果方块底下三格有流体那直接不执行
								if(!isLiquid) {
									for(int blockPosY = 1; blockPosY <= 3; blockPosY++) {
										if(!(BlockUtils.getBlock(new BlockPos(x, y - blockPosY, z)) instanceof BlockLiquid) && AutoMinePathFinder.isSafeToWalkOn(new BlockPos(x, y - blockPosY, z))) {
											canBreak = true;
										}
									}
								}

								//方块周围不能是流体
								loop:
								for (int x1 = x - 2; x1 <= x + 2; x1++)
								{
									for (int y1 = y; y1 <= y + 2; y1++)
									{
										for (int z1 = z - 2; z1 <= z + 2; z1++)
										{
											if (BlockUtils.getBlock(new BlockPos(x1, y1, z1)) instanceof BlockLiquid)
											{
												canBreak = false;
												break loop;
											}
										}
									}
								}

								if(canBreak) {
									blocks.add(pos);
								}
							}
						}
					}
				}
			}
		}


        if(!blocks.isEmpty()) {
        	//排序，离玩家最近的为blocks[0]
        	blocks.sort(Comparator.comparingDouble(pos -> BlockUtils.getBlockDistance((float)(Wrapper.INSTANCE.mc().player.posX - pos.getX()), (float)(Wrapper.INSTANCE.mc().player.posY - pos.getY()), (float)(Wrapper.INSTANCE.mc().player.posZ - pos.getZ()))));
    		start = true;
        }
    	
    	new Thread() {
    		public void run() {
    			while(!start) {
    				if(Wrapper.INSTANCE.mc().world == null) {
    					return;
    				}
    			}
    			
    			if(Wrapper.INSTANCE.mc().world == null) {
					return;
				}
    			
    			readyBreakBlock = blocks.get(0);
    			if(BlockUtils.getNeaestPlayerBlockDistance(readyBreakBlock.getX(), readyBreakBlock.getY(), readyBreakBlock.getZ()) > 2) {
        			Vec3 topFrom = new Vec3(Wrapper.INSTANCE.mc().player.posX, Wrapper.INSTANCE.mc().player.posY, Wrapper.INSTANCE.mc().player.posZ);
                    Vec3 to = new Vec3(readyBreakBlock.getX(), readyBreakBlock.getY(), readyBreakBlock.getZ());
                    path = computePath(topFrom, to, 8);
                    if(path.get(path.size() - 1).squareDistanceTo(to) > 0.25) {
                    	tryTwo = true;
                        Vec3 twice = path.get(path.size() - 1);
                        for(Vec3 vec3 : computePath(twice, to, 0)) {
                        	path.add(vec3);
                        }
                    }
        			tryTwo = false;
        		}
    			PathReady = true;
        		return;
    		};
    	}.start();
    }
    public void onDisableMod()
    {

    	//isActive = false;
		//refresh.reset();
    	resetAllOptions();
    }
    @Override
	public void onClientTick(ClientTickEvent event)
	{
    	
    	if(start && PathReady) {
    		if(shouldPlaceBlock) {
    			Wrapper.INSTANCE.mc().player.rotationPitch = 90f;
    			placeBlock();
        	}
    		
    		if((readyBreakBlock != null && BlockUtils.getBlock(readyBreakBlock) == Block.getBlockById(0)) || Wrapper.INSTANCE.mc().player.isDead) {
    			new Thread() {
    				public void run() {
    					try {
    						onDisableMod();
    						sleep(500L);
    						onEnableMod();
    						return;
    					} catch (Exception e) {}
    				};
    			}.start();
    			return;
    		}
    		
    		//一直停滞在原地
    		if(Wrapper.INSTANCE.mc().player.motionX == 0D && (Wrapper.INSTANCE.mc().player.motionY == -0.1552320045166016 || Wrapper.INSTANCE.mc().player.motionY == -0.0784000015258789) && Wrapper.INSTANCE.mc().player.motionZ == 0D) {
    			if(timeHelper2.hasReach(10000L)) {
    				new Thread() {
    					public void run() {
    						try {
    							onDisableMod();
    							sleep(1000L);
    							onEnableMod();
    							keyDown = "W";
    							sleep(1000L);
    							keyDown = "";
    							return;
    						} catch (Exception e) {}
    					};
    				}.start();
    			}
    		}else {
    			timeHelper2.reset();
    		}
    		
    		if(!timeHelper4.hasReach(delay.getValue())) {
    			return;
    		}
    		
			int posX = (int)Wrapper.INSTANCE.mc().player.posX;
			int posY = (int)Wrapper.INSTANCE.mc().player.posY;
			int posZ = (int)Wrapper.INSTANCE.mc().player.posZ;
			BlockPos pos = Wrapper.INSTANCE.mc().objectMouseOver.getBlockPos();
			
    		if(path.size() < 1 || path.get(path.size() - 1).squareDistanceTo(new Vec3(posX, posY, posZ)) < 1.51) {
    			for (int x1 = posX - 2; x1 <= posX + 2; x1++)
                {
        			for (int y1 = posY - 1; y1 <= posY + 2; y1++)
                    {
        				for (int z1 = posZ - 2; z1 <= posZ + 2; z1++)
                        {
                        	if(BlockUtils.getBlock(readyBreakBlock) == BlockUtils.getBlock(new BlockPos(x1, y1, z1))) {
                    			BlockUtils.faceBlockClient(readyBreakBlock);
                    			Wrapper.INSTANCE.mc().player.rotationYaw += 0.5f;
                    			breakBlockWithHand(pos);
                    			return;
                    		}
                        }
                    }
                }
    			if(BlockUtils.getNeaestPlayerBlockDistance(readyBreakBlock.getX(), readyBreakBlock.getY(), readyBreakBlock.getZ()) < 2) {
    				BlockUtils.faceBlockClient(readyBreakBlock);
        			Wrapper.INSTANCE.mc().player.rotationYaw += 0.5f;
        			breakBlockWithHand(pos);
        			return;
    			}
    		}
    		
    		//遇到沙子
    		if(BlockUtils.getBlock(new BlockPos(Wrapper.INSTANCE.mc().player)) instanceof BlockGravel) {
    			breakBlockWithHand(pos);
    			return;
    		}
    		
    		Vec3 vec3 = path.get(count < path.size() - 1 ? count : path.size() - 1);
			Vec3 player = new Vec3(Wrapper.INSTANCE.mc().player.posX, Wrapper.INSTANCE.mc().player.posY + 0.5, Wrapper.INSTANCE.mc().player.posZ);
			if(vec3.squareDistanceTo(player) < 0.4) {
				keyDown = "";
				count++;
			}else {
				if(Wrapper.INSTANCE.mc().player.posY == vec3.getY()) {
					faceEntity(vec3.getX(), vec3.getY(), vec3.getZ());
    				if(BlockUtils.getNeaestPlayerBlockDistance(pos.getX(), pos.getY(), pos.getZ()) < 1 && (Wrapper.INSTANCE.mc().objectMouseOver != null && BlockUtils.getBlock(Wrapper.INSTANCE.mc().objectMouseOver.getBlockPos()) instanceof BlockSand || BlockUtils.getBlock(Wrapper.INSTANCE.mc().objectMouseOver.getBlockPos()) instanceof BlockGravel)) {
    					keyDown = "";
    					timeHelper.reset();
    	    		}else {
    	    			if(timeHelper.hasReach(800L)) {
    	    				keyDown = "W";
    					}
    	    		}
    				if(BlockUtils.getNeaestPlayerBlockDistance(pos.getX(), pos.getY(), pos.getZ()) < 1.25) {
            			keyDown = "";
    					breakBlockWithHand(pos);
    				}else {
    					keyDown = "W";
    				}
				}else if(vec3.getY() > Wrapper.INSTANCE.mc().player.posY) {
					keyDown = "W";
					if(BlockUtils.getBlock(new BlockPos(Wrapper.INSTANCE.mc().player).up(2)) instanceof BlockAir || BlockUtils.getBlock(new BlockPos(Wrapper.INSTANCE.mc().player).down()) instanceof BlockAir) {
				    	//必须有方块
				    	if(!hasBlock()) {
				    		onDisableMod();
				    		ChatUtils.message("§c物品栏的踮脚方块没了！！！赶紧补上！");
				    		return;
				    	}
						shouldPlaceBlock = true;
						keyDown = "SPACE";
					}else if(!(BlockUtils.getBlock(new BlockPos(Wrapper.INSTANCE.mc().player).up(2)) instanceof BlockAir) && !(BlockUtils.getBlock(new BlockPos(Wrapper.INSTANCE.mc().player).down()) instanceof BlockAir)) {
						faceEntity(vec3.getX(), vec3.getY() + 1, vec3.getZ());
        				if(BlockUtils.getNeaestPlayerBlockDistance(pos.getX(), pos.getY(), pos.getZ()) < 2) {
        					breakBlockWithHand(pos);
        				}
    					keyDown = "";
					}
				}else if(vec3.getY() < Wrapper.INSTANCE.mc().player.posY) {
					keyDown = "";
					faceEntity(vec3.getX(), vec3.getY() - 1, vec3.getZ());
					if(BlockUtils.getNeaestPlayerBlockDistance(pos.getX(), pos.getY(), pos.getZ()) > 2) {
						if(timeHelper3.hasReach(1000L)) {
							keyDown = "W";
						}
					}else {
						timeHelper3.reset();
					}
    				if(BlockUtils.getNeaestPlayerBlockDistance(pos.getX(), pos.getY(), pos.getZ()) < 2) {
    					timeHelper3.reset();
    					breakBlockWithHand(pos);
    				}
				}
			}
			
			if(shouldPlaceBlock) {
    			Wrapper.INSTANCE.mc().player.rotationPitch = 90f;
    			placeBlock();
        	}
    	}else {
    		count = 0;
    	}
	}
	@Override
	public void onInputUpdate(InputUpdateEvent event) {

		if(AutoMine.keyDown.equalsIgnoreCase("")) {
			return;
		}

		MovementInput input = event.getMovementInput();
		input.moveStrafe = 0.0F;
		input.moveForward = 0.0F;

		if(AutoMine.keyDown.equalsIgnoreCase("W")) {
			++input.moveForward;
		}
		if(AutoMine.keyDown.equalsIgnoreCase("S")) {
			--input.moveForward;
		}
		if(AutoMine.keyDown.equalsIgnoreCase("A")) {
			++input.moveStrafe;
		}
		if(AutoMine.keyDown.equalsIgnoreCase("D")) {
			--input.moveStrafe;
		}
		input.jump = AutoMine.keyDown.equalsIgnoreCase("SPACE");
		input.sneak = AutoMine.keyDown.equalsIgnoreCase("SHIFT");
		if(input.sneak) {
			input.moveStrafe = (float)((double)input.moveStrafe * 0.3D);
			input.moveForward = (float)((double)input.moveForward * 0.3D);
		}
		input.moveStrafe *= 5.0F;
		input.moveForward *= 5.0F;

	}
    public static void faceEntity(double xp, double yp, double zp)
    {
		Minecraft mc = Minecraft.getMinecraft();
    	double x = xp - Wrapper.INSTANCE.mc().player.posX;
        double y = yp - Wrapper.INSTANCE.mc().player.posY;
        double z = zp - Wrapper.INSTANCE.mc().player.posZ;
        double d1 = Wrapper.INSTANCE.mc().player.posY + Wrapper.INSTANCE.mc().player.getEyeHeight() - yp - 0.8;
        double d3 = Math.sqrt(x * x + z * z);
        //左右角度
        float f = (float)(Math.atan2(z, x) * 180.0D / Math.PI) - 90.0F;
        //上下角度
        float f1 = (float)(Math.atan2(d1, d3) * 180.0D / Math.PI);
        Wrapper.INSTANCE.mc().player.rotationYaw = f;
    	Wrapper.INSTANCE.mc().player.rotationPitch = f1;
    }
	public void placeBlock()
	{
    	BlockPos blockDown = new BlockPos(Wrapper.INSTANCE.mc().player).down();
        if (!BlockUtils.getBlock(blockDown).getMaterial(zelix.utils.BlockUtils.getState(blockDown)).isReplaceable()) return;


		int newSlot = -1;
        for (int i = 0; i < 9; ++i) {
            final ItemStack stack = Wrapper.INSTANCE.mc().player.inventory.getStackInSlot(i);
			if (stack.getItem() instanceof ItemBlock){
				if (!(((ItemBlock) stack.getItem()).getBlock() instanceof BlockOre)){
					newSlot = i;
				}
			}

        }
        if (newSlot == -1) return;

		//int newSlot = 2;
        final int oldSlot = Wrapper.INSTANCE.mc().player.inventory.currentItem;
        Wrapper.INSTANCE.mc().player.inventory.currentItem = newSlot;
        shouldPlaceBlock = true;
        Vec3d eyesPos = new Vec3d(Wrapper.INSTANCE.mc().player.posX, Wrapper.INSTANCE.mc().player.posY + Wrapper.INSTANCE.mc().player.getEyeHeight(), Wrapper.INSTANCE.mc().player.posZ);
		EnumFacing[] values;
		for (int length = (values = EnumFacing.values()).length, i = 0; i < length; ++i) {
			EnumFacing side = values[i];
			BlockPos neighbor = blockDown.offset(side);
			EnumFacing side2 = side.getOpposite();
			if (eyesPos.squareDistanceTo(new Vec3d(blockDown).addVector(0.5, 0.5, 0.5)) < eyesPos
					.squareDistanceTo(new Vec3d(neighbor).addVector(0.5, 0.5, 0.5)) && BlockUtils.getBlock(neighbor).canCollideCheck(Wrapper.INSTANCE.mc().world.getBlockState(neighbor), false)) {
				Vec3d hitVec = new Vec3d(neighbor).addVector(0.5, 0.5, 0.5)
						.add(new Vec3d(side2.getDirectionVec()).scale(0.5));
				if (eyesPos.squareDistanceTo(hitVec) <= 18.0625) {
					Wrapper.INSTANCE.mc().player.swingArm(EnumHand.MAIN_HAND);
					Wrapper.INSTANCE.controller().processRightClickBlock(Wrapper.INSTANCE.mc().player, Wrapper.INSTANCE.mc().world, neighbor,side2, new Vec3d(hitVec.x,hitVec.y,hitVec.z),EnumHand.MAIN_HAND);
					for (String fieldName : new String[] {"field_78781_i", "blockHitDelay"}) {
			            try {
							Field f = PlayerControllerMP.class.getDeclaredField(fieldName);
							f.setAccessible(true);
							f.set(Wrapper.INSTANCE.controller(), 4);
			            }catch (Exception e) {}
			        }
					shouldPlaceBlock = false;
				}
			}
		}
        Wrapper.INSTANCE.mc().player.inventory.currentItem = oldSlot;
	}
    public static void glColor(int color)
	{
        GL11.glColor4f((color >> 16 & 0xFF) / 255.0F, (color >> 8 & 0xFF) / 255.0F, (color & 0xFF) / 255.0F, (color >> 24 & 0xFF) / 255.0F);
    }
	public boolean isTarget(BlockPos pos) {
		Block block = Wrapper.INSTANCE.mc().world.getBlockState(pos).getBlock();
		if (Blocks.DIAMOND_ORE.equals(block)) {
			return dia.getValue();
		} else if (Blocks.LAPIS_ORE.equals(block)) {
			return lapis.getValue();
		} else if (Blocks.IRON_ORE.equals(block)) {
			return iron.getValue();
		} else if (Blocks.GOLD_ORE.equals(block)) {
			return gold.getValue();
		} else if (Blocks.COAL_ORE.equals(block)) {
			return coal.getValue();
		} else if (Blocks.EMERALD_ORE.equals(block)) {
			return emerald.getValue();
		} else if (Blocks.REDSTONE_TORCH.equals(block) || Blocks.LIT_REDSTONE_ORE.equals(block)) {
			return redstone.getValue();
		} else if (Blocks.QUARTZ_ORE.equals(block)) {
			return quartz.getValue();
		}

		return false;
	}
	@Override
	public void onRenderWorldLast(RenderWorldLastEvent event)
    {
    	
    	if (!path.isEmpty() && start)
        {
    		try {
    			if(showPath.getValue()) {
					Search.renderBlock(readyBreakBlock,event);
    				GL11.glPushMatrix();
    		        GL11.glEnable(GL11.GL_BLEND);
    		        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
    		        GL11.glShadeModel(GL11.GL_SMOOTH);
    		        GL11.glDisable(GL11.GL_TEXTURE_2D);
    		        GL11.glEnable(GL11.GL_LINE_SMOOTH);
    		        GL11.glDisable(GL11.GL_DEPTH_TEST);
    		        GL11.glDisable(GL11.GL_LIGHTING);
    		        GL11.glDepthMask(false);
    		        GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
    				glColor(-131);
                	GL11.glPushMatrix();
            		GL11.glLineWidth(2.5F);
            		GL11.glDisable(GL11.GL_TEXTURE_2D);
            		GL11.glDisable(GL11.GL_LIGHTING);
            		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
            		GL11.glEnable(GL11.GL_LINE_SMOOTH);
            		GL11.glEnable(GL11.GL_BLEND);
            		GL11.glDisable(GL11.GL_DEPTH_TEST);
            		GL11.glBegin(GL11.GL_LINE_STRIP);
            		for(Vec3 pos : path) {
            			GL11.glVertex3d(pos.getX() - Wrapper.INSTANCE.mc().player.posX, pos.getY()  - Wrapper.INSTANCE.mc().player.posY, pos.getZ() - Wrapper.INSTANCE.mc().player.posZ);
                    }
            		GL11.glEnd();	
            		GL11.glEnable(GL11.GL_DEPTH_TEST);
            		GL11.glDisable(GL11.GL_LINE_SMOOTH);
            		GL11.glDisable(GL11.GL_BLEND);
            		GL11.glEnable(GL11.GL_TEXTURE_2D);
            		GL11.glEnable(GL11.GL_LIGHTING);
            		GL11.glPopMatrix();
            		GL11.glDepthMask(true);
                    GL11.glEnable(GL11.GL_DEPTH_TEST);
                    GL11.glDisable(GL11.GL_LINE_SMOOTH);
                    GL11.glEnable(GL11.GL_TEXTURE_2D);
                    GL11.glDisable(GL11.GL_BLEND);
                    GL11.glPopMatrix();
                    GL11.glColor4f(1, 1, 1, 1);
    			}
			} catch (Exception e) {}
        }
    }
    private ArrayList<Vec3> computePath(Vec3 topFrom, Vec3 to, int everyDistance)
    {
        AutoMinePathFinder pathfinder = new AutoMinePathFinder(topFrom, to);
        pathfinder.compute();
        int i = 0;
        Vec3 lastLoc = null;
        Vec3 lastDashLoc = null;
        ArrayList<Vec3> path = new ArrayList<Vec3>();
        ArrayList<Vec3> pathFinderPath = pathfinder.getPath();

        for (Vec3 pathElm : pathFinderPath)
        {
            if (i == 0 || i == pathFinderPath.size() - 1)
            {
                if (lastLoc != null)
                {
                    path.add(lastLoc.addVector(0.5, 0, 0.5));
                }

                path.add(pathElm.addVector(0.5, 0, 0.5));
                lastDashLoc = pathElm;
            }
            else
            {
                boolean canContinue = true;

                if (pathElm.squareDistanceTo(lastDashLoc) > (everyDistance * everyDistance))
                {
                    canContinue = false;
                }
                else
                {
                    double smallX = Math.min(lastDashLoc.getX(), pathElm.getX());
                    double smallY = Math.min(lastDashLoc.getY(), pathElm.getY());
                    double smallZ = Math.min(lastDashLoc.getZ(), pathElm.getZ());
                    double bigX = Math.max(lastDashLoc.getX(), pathElm.getX());
                    double bigY = Math.max(lastDashLoc.getY(), pathElm.getY());
                    double bigZ = Math.max(lastDashLoc.getZ(), pathElm.getZ());
                    cordsLoop:

                    for (int x = (int) smallX; x <= bigX; x++)
                    {
                        for (int y = (int) smallY; y <= bigY; y++)
                        {
                            for (int z = (int) smallZ; z <= bigZ; z++)
                            {
                                if (!AutoMinePathFinder.checkPositionValidity(x, y, z, true))
                                {
                                    canContinue = false;
                                    break cordsLoop;
                                }
                            }
                        }
                    }
                }

                if (!canContinue)
                {
                    path.add(lastLoc.addVector(0.5, 0, 0.5));
                    lastDashLoc = lastLoc;
                }
            }

            lastLoc = pathElm;
            i++;
        }

        return path;
    }
    private void breakBlockWithHand(BlockPos pos)
	{
		//选择最优工具
    	if(Wrapper.INSTANCE.mc().objectMouseOver != null) {
    		if(Wrapper.INSTANCE.mc().objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK) {
        		Block block = BlockUtils.getBlock(Wrapper.INSTANCE.mc().objectMouseOver.getBlockPos());
                if(block != null && block != Block.getBlockById(0)) {
                   float ChangSpeed = 1.0F;
                   int Item = -1;

                   for(int SelectItem = 0; SelectItem < 9; ++SelectItem) {
                      ItemStack stack = Wrapper.INSTANCE.mc().player.inventory.getStackInSlot(SelectItem);
                      if(stack != null) {
                         float speed = stack.getItem().getDestroySpeed(stack,Block.getStateById(Block.getIdFromBlock(block)));
                         if(speed > ChangSpeed) {
                            ChangSpeed = speed;
                            Item = SelectItem;
                         }
                      }
                   }

                   if(Item != -1) {
                      Wrapper.INSTANCE.mc().player.inventory.currentItem = Item;
                   }
                }
        	}else if(Wrapper.INSTANCE.mc().objectMouseOver.typeOfHit == RayTraceResult.Type.ENTITY) {
				NonNullList<ItemStack> inventory = Wrapper.INSTANCE.mc().player.inventory.mainInventory;
                int currentBest = 0;
                int diamond = -1;
                int iron = -1;
                int stone = -1;
                int wood = -1;

                while(currentBest < 9) {
                   if(inventory.get(currentBest) == null) {
                      ++currentBest;
                   } else {
                      Item item = inventory.get(currentBest).getItem();
                      if(item instanceof ItemSword) {
                         int id = Item.getIdFromItem(item);
                         if(id == 276) {
                            diamond = currentBest;
                         }

                         if(id == 267) {
                            iron = currentBest;
                         }

                         if(id == 272) {
                            stone = currentBest;
                         }

                         if(id == 268) {
                            wood = currentBest;
                         }
                      }

                      ++currentBest;
                   }
                }

                int itemIndex = diamond >= 0 ? diamond : (iron >= 0 ? iron : (stone >= 0 ? stone : (wood >= 0 ? wood : -1)));
                if(itemIndex != -1) {
                	Wrapper.INSTANCE.mc().player.inventory.currentItem = itemIndex;
                }
        	}
    	}
    	
		Wrapper.INSTANCE.mc().player.swingArm(EnumHand.MAIN_HAND);
    	Wrapper.INSTANCE.controller().onPlayerDamageBlock(pos, getDirectionFromEntityLiving(pos, Wrapper.INSTANCE.mc().player));
    }
    private boolean hasBlock()
	{
    	for(int i = 0; i < 9; i++) {
    		final ItemStack stack = Wrapper.INSTANCE.mc().player.inventory.getStackInSlot(i);
            if(stack != null && stack.getItem() instanceof ItemBlock && !(Block.getBlockFromItem(stack.getItem()) instanceof BlockOre)) {
            	return true;
            }
    	}
    	return false;
    }
    private void resetAllOptions()
	{
    	path.clear();
    	blocks.clear();
    	readyBreakBlock = null;
    	start = false;
    	PathReady = false;
    	shouldPlaceBlock = false;
    	count = 0;
    	tryTwo = false;
    	timeHelper.reset();
    	timeHelper2.reset();
    	timeHelper3.reset();
    	timeHelper4.reset();
    	keyDown = "";
    }
	public static EnumFacing getDirectionFromEntityLiving(BlockPos pos, EntityLivingBase placer)
	{
		if (Math.abs(placer.posX - (double)((float)pos.getX() + 0.5F)) < 2.0D && Math.abs(placer.posZ - (double)((float)pos.getZ() + 0.5F)) < 2.0D)
		{
			double d0 = placer.posY + (double)placer.getEyeHeight();

			if (d0 - (double)pos.getY() > 2.0D)
			{
				return EnumFacing.UP;
			}

			if ((double)pos.getY() - d0 > 0.0D)
			{
				return EnumFacing.DOWN;
			}
		}

		return placer.getHorizontalFacing().getOpposite();
	}
}